<template>
  <div class="image-upload">
    <!-- :on-change="onChange" -->
    <!-- 
      accept 接收值类型如下：

      文件后缀名：.jpg  .png  .gif

      image/*  任何图片
      audio/*  任何音频
      video/*  任何视频

      补充说明：
      虽然 accept 可以限制用户选择规定的文件类型，但是 操作系统的 文件选择对话框 也可以调整 可选文件类型 为 所有文件类型，
      所以，这个选项只能尽量避免用户选错文件类型（在不调整可选文件类型的情况下），
      所以，还是在 :before-upload 钩子函数中判断最安全
      那，这个 accept 属性还要不要加呢？  要，因为可以提升用户体验
     -->

    <!-- :on-progress="onProgress" 仅在 非自定义上传行为时 生效 -->
    <el-upload
      action="#"
      :class="{ hide: hideUploadBtn }"
      list-type="picture-card"
      :file-list="fileList"
      :limit="limit"
      :on-preview="preview"
      :on-remove="onRemove"
      accept="image/*"
      :before-upload="onBeforeUpload"
      :http-request="onHTTPRequest"
      :on-success="onSuccess"
      :on-error="onError"
    >
      <i class="el-icon-plus"></i>
    </el-upload>
    <div
      v-show="loading"
      style="
        position: absolute;
        top: 0;
        left: 0;
        width: 148px;
        height: 148px;
        display: flex;
        border-radius: 6px;
        justify-content: center;
        align-items: center;
        background-color: rgba(0, 0, 0, 0.5);
      "
    >
      <el-progress
        type="dashboard"
        :percentage="percentage"
        :color="[
          { color: '#f56c6c', percentage: 20 },
          { color: '#e6a23c', percentage: 40 },
          { color: '#5cb87a', percentage: 60 },
          { color: '#1989fa', percentage: 80 },
          { color: '#6f7ad3', percentage: 100 },
        ]"
      ></el-progress>
    </div>
    <el-dialog :visible.sync="showDialog" :show-close="false">
      <img :src="imgUrl" alt="" style="width: 100%" />
    </el-dialog>
  </div>
</template>

<script>
import COS from 'cos-js-sdk-v5';
const cos = new COS({
  SecretId: 'AKIDVoxta1FIBrJXWDgy1pNhofHUVIOErGPJ',
  SecretKey: 'lJdhYBZ5MQGrBIAoCNJ0rUu51jGbjdLq',
});

export default {
  name: 'ImageUpload',
  model: {
    prop: 'value',
    event: 'input',
  },
  props: {
    value: {
      type: String | Array,
    },
    limit: {
      type: Number,
      default: 1,
    },
  },
  data() {
    // props 在 data 之前解析

    let fileList = [];
    if (!!this.value) {
      if (this.limit === 1) {
        fileList.push({ url: this.value });
      } else {
        fileList = this.value.map(v => ({ url: v }));
      }
    }

    return {
      percentage: 0, // 上传进度百分比 0-100
      loading: false, // 是否正在上传中
      showDialog: false,
      fileList,
      imgUrl: '',
    };
  },
  computed: {
    hideUploadBtn() {
      // 如果正在上传中，或者 已上传的文件列表的长度 等于 最大限制数量 就隐藏上传按钮
      return this.loading || this.fileList.length === this.limit;
    },
  },
  watch: {
    // value: {
    //   immediate: true,
    //   handler() {
    //     let fileList = [];
    //     if (!!this.value) {
    //       if (typeof this.value === 'string') {
    //         fileList.push({ url: this.value });
    //       } else {
    //         fileList = this.value.map(v => ({ url: v }));
    //       }
    //     }
    //     this.fileList = fileList;
    //   },
    // },
  },
  methods: {
    onBeforeUpload(file) {
      if (!/^image\/.+$/.test(file.type)) {
        this.$message.warning('只能选择图片类型的文件');
        return false;
      }
      // 单位：Byte
      if (file.size > 1024 * 1024 * 5) {
        this.$message.warning('图片大小不能超过 5 M');
        return false;
      }
      return true;
    },
    async onHTTPRequest(data) {
      this.loading = true;

      const { file } = data;

      // 不能直接将 file push 到 this.fileList 中，因为 这里的 file 是一个 File 对象 图片会出现白板，而 this.fileList 中应该保存的数据格式为： [ { url, status }, ... ]
      // this.fileList.push(file);

      // // 模拟延迟3s，发现 el-upload 是你选择文件后，立即显示在文件列表中了，用本地图片地址 预览 在本地了
      // await new Promise(resolve => {
      //   setTimeout(resolve, 3000);
      // });

      const { Location } = await cos.putObject({
        Bucket: 'leimf-001-1317063555', // 哪个桶
        Region: 'ap-guangzhou', // 哪个地域
        Key: `${file.uid}_${file.name}`, // 上传的唯一键名
        Body: file, // 文件对象
        onProgress: params => {
          this.percentage = Math.floor(params.percent * 100);
        },
      });

      // 调后端API

      // 如果 不返回 或者 返回一个正常的数据 那么会进入 :on-success
      // return 123;

      // 基于 Promise 执行逻辑，如果 返回一个 rejected 状态的 promise 或者 手动抛出异常 都会进入 :on-error
      // return Promise.reject(new Error('上传失败，请稍后重试~'));
      // throw new Error('上传失败，请稍后重试~')

      this.loading = false;

      return `http://${Location}`;
    },
    // 如果是用 :http-request 自定义的上传动作 其处理函数的返回值 会作为 :on-success 的 response
    onSuccess(response, file, fileList) {
      this.fileList = fileList;
      if (typeof this.value === 'string') {
        this.$emit('input', file.response);
      } else {
        this.$emit(
          'input',
          fileList.map(v => v.response || v.url)
        );
      }
      this.$emit('success', { response, file, fileList });
    },
    onError(err, file, fileList) {
      this.$message.error('图片上传失败，请稍后重试~');
    },
    onRemove(file, fileList) {
      this.fileList = fileList;
      if (typeof this.value === 'string') {
        this.$emit('input', '');
      } else {
        this.$emit(
          'input',
          fileList.map(v => v.response || v.url)
        );
      }
    },
    // onChange(file, fileList) {

    //   // 失败触发的时候，push 一次可以
    //   // if (fileList.length === 0) {
    //   //   this.fileList.push(file);
    //   // }

    //   // 添加文件的时候，push 一次不行
    //   // if (!this.fileList.some(v => v.uid === file.uid)) {
    //   //   this.fileList.push(file);
    //   // }

    //   // 连续 push 两次 又可以
    //   // this.fileList.push(file);
    // },
    preview(file) {
      this.imgUrl = file.url;
      this.showDialog = true;
    },
  },
};
</script>

<style lang="scss" scoped>
.image-upload {
  position: relative;

  ::v-deep .el-progress__text {
    color: white;
  }

  ::v-deep .el-dialog__header {
    background: transparent;
  }

  ::v-deep .el-dialog__body {
    padding: 0;
  }

  .hide {
    ::v-deep .el-upload--picture-card {
      display: none;
    }
  }
}
</style>
